package com.itcam.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

/**
 * java配置类，替代xml配置文件
 * 1.包扫描注解配置
 * 2.引用外部的配置文件
 * 3.声明第三方依赖的bean组件
 * <p>
 * 步骤一：添加@Configuration代表配置类
 * 步骤二：实现上面的三个功能注解
 */

//@ComponentScan(value = "com.itcam.ioc_01")
//@ComponentScan({"com.itcam.ioc_01","com.itcam.ioc_02"})
@ComponentScan("com.itcam.ioc_01")
@PropertySource(value = "classpath:jdbc.properties")
@Configuration
public class JavaConfigration {

    @Value("${itcam.url}")
    private String url;
    @Value("${itcam.driver}")
    private String driver;
    @Value("${itcam.username}")
    private String username;
    @Value("${itcam.password}")
    private String password;

    /**
     * <bean  ->  一个方法
     * <p>
     * 方法的返回值类型 == bean组件的类型或者他的接口和父类
     * 方法的名字 = bean的id
     * <p>
     * 方法体可以自定义实现过程即可！
     * 最重要的一步：@Bean会真正让配置类的方法创建的组件存储到ioc容器
     * <p>
     * 问题1：beanName的问题
     * 默认： 方法名
     * 指定： name/value属性起名字，覆盖方法名
     * 问题2：周期方法如何指定
     * 原有注解方案：@PostConstruct + @PreDestroy 注解指定
     * bean属性指定方案：initMethod / destroyMethod指定
     * 问题3：作用域
     * 和以前一样@Scope注解，默认是单例
     * 问题4：如何引用其他的ioc组件
     * 直接调用对方的bean方法即可
     * 直接形参变量进行引入，要求必须有对应的组件，如果有多个，形参名 = 组件id表示即可
     *
     * @return
     */
    @Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) // 多例
    @Bean(name = "Jerry", initMethod = "", destroyMethod = "")
    public DruidDataSource dataSource() {


        // 实现具体的实例化过程
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        dataSource.setUsername(username);
        dataSource.setPassword(password);

        return dataSource();
    }

    @Bean(name = "Tom")
    public DruidDataSource dataSource1() {


        // 实现具体的实例化过程
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setDriverClassName(driver);
        dataSource.setUsername(username);
        dataSource.setPassword(password);

        return dataSource();
    }

    @Bean
    public JdbcTemplate jdbcTemplate() {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        // 需要DataSource 需要ioc容器的其他组件
        // 方案1:如果其他组件也是@Bean方法，可以直接调用 | 本质上是从ioc容器获取组件，要求对方也是@Bean
        jdbcTemplate.setDataSource(dataSource());
        return jdbcTemplate;
    }

    @Bean
    public JdbcTemplate jdbcTemplate1(DataSource Jerry, DataSource Tom) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        // 需要DataSource 需要ioc容器的其他组件
        // 方案2:形参列表声明想要的组件类型，可以是一个也可以是多个！ioc容器也会注入
        //      如果没有@Bean：形参变量注入，要求必须有对应的类型的组件，如果没有抛异常
        //      如果有多个@Bean：可以使用形参名称等同于对应的beanId标识即可
        jdbcTemplate.setDataSource(dataSource());
        return jdbcTemplate;
    }
}
